package com.tpl.core.basedata.common;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.ibatis.executor.statement.StatementHandler;
import org.apache.ibatis.mapping.BoundSql;
import org.apache.ibatis.plugin.*;
import org.apache.ibatis.reflection.DefaultReflectorFactory;
import org.apache.ibatis.reflection.MetaObject;
import org.apache.ibatis.reflection.ReflectorFactory;
import org.apache.ibatis.reflection.factory.DefaultObjectFactory;
import org.apache.ibatis.reflection.factory.ObjectFactory;
import org.apache.ibatis.reflection.wrapper.DefaultObjectWrapperFactory;
import org.apache.ibatis.reflection.wrapper.ObjectWrapperFactory;
import org.apache.ibatis.session.RowBounds;

import java.sql.Connection;
import java.util.Map;
import java.util.Properties;


@Intercepts({@Signature(type=StatementHandler.class,method="prepare",args={Connection.class,Integer.class})})
public class PaginationInterceptor implements Interceptor {

	private final static Log log = LogFactory.getLog(PaginationInterceptor.class);
	private static final ObjectFactory DEFAULT_OBJECT_FACTORY = new DefaultObjectFactory();
    private static final ObjectWrapperFactory DEFAULT_OBJECT_WRAPPER_FACTORY = new DefaultObjectWrapperFactory();
    private static final ReflectorFactory DEFAULT_REFLECTOR_FACTOR=new DefaultReflectorFactory();
	@Override
	@SuppressWarnings({ "rawtypes", "unchecked" })
	public Object intercept(Invocation invocation) throws Throwable {
		StatementHandler statementHandler = (StatementHandler)invocation.getTarget();
		BoundSql boundSql = statementHandler.getBoundSql();
		MetaObject metaStatementHandler = MetaObject.forObject(statementHandler, DEFAULT_OBJECT_FACTORY, DEFAULT_OBJECT_WRAPPER_FACTORY,DEFAULT_REFLECTOR_FACTOR);
		Object params=boundSql.getParameterObject();
		if(!(params instanceof Map)){
			return invocation.proceed();
		}
		
//		Map oldParams=(Map)params;
//		Map newParams=new HashMap();
//		for(Object pkey : oldParams.keySet()){
//			Object p=oldParams.get(pkey);
//			if(p!=null&&!Common.isWrapClass(p.getClass())&&(p instanceof Serializable)){
//				Map fieldMapper=Common.getFieldMapper((Serializable)p);
//				newParams.putAll(fieldMapper);
//			}
//		}
//		oldParams.putAll(newParams);
		Map _params=(Map)params;
		Object start=_params.containsKey("pageIndex")?_params.get("pageIndex"):null;
		Object limit=_params.containsKey("pageSize")?_params.get("pageSize"):null;
		if(start==null||limit==null)//判断参数
			return invocation.proceed();
		initDialect(boundSql, metaStatementHandler, start, limit);
//		
		return invocation.proceed();
	}

	private void initDialect(BoundSql boundSql,
                             MetaObject metaStatementHandler, Object start, Object limit) {
		String originalSql = (String)metaStatementHandler.getValue("delegate.boundSql.sql");
		metaStatementHandler.setValue("delegate.boundSql.sql", getLimitString(originalSql, Integer.valueOf(start.toString()), Integer.valueOf(limit.toString())) );
		metaStatementHandler.setValue("delegate.rowBounds.offset", RowBounds.NO_ROW_OFFSET );
		metaStatementHandler.setValue("delegate.rowBounds.limit", RowBounds.NO_ROW_LIMIT );
		if(log.isDebugEnabled()){
			log.debug("生成分页SQL : " + boundSql.getSql());
		}
	}
	public String getLimitString(String sql, int pageIndex, int pageSize) {
		if(pageSize<=0)return sql;
		int start=pageIndex*pageSize;
		sql = sql.trim();
		boolean isForUpdate = false;
		if (sql.toLowerCase().endsWith(" for update")) {
			sql = sql.substring(0, sql.length() - 11);
			isForUpdate = true;
		}

		StringBuffer selectSql = new StringBuffer(sql.length() + 100);
		selectSql.append(sql).append(" LIMIT ").append(start).append(",").append(pageSize);

		if (isForUpdate) {
			selectSql.append(" for update");
		}

		return selectSql.toString();
	}

	@Override
	public Object plugin(Object target) {
		return Plugin.wrap(target, this);
	}

	@Override
	public void setProperties(Properties properties) {
	}

}
